package tech.xs.common.framework.util;


import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import tech.xs.common.framework.domain.constant.HttpHeaderKey;
import tech.xs.common.framework.domain.constant.Symbol;
import tech.xs.common.framework.holder.SpringContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class DynamicRequestUtil {

    public static <T> ResponseEntity<T> post(String serviceName, String uri, String body, Class<T> responseType) {
        HttpEntity<String> requestEntity = new HttpEntity<>(body, makeHeader());
        LoadBalancerClient loadBalancerClient = SpringContextHolder.getBean(LoadBalancerClient.class);
        ServiceInstance serviceInstance = loadBalancerClient.choose(serviceName);
        String url = String.format("http://%s:%s", serviceInstance.getHost(), serviceInstance.getPort()) + uri;
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate.postForEntity(url, requestEntity, responseType);
    }

    public static <T> ResponseEntity<T> get(String serviceName, String uri, Map<String, ?> requestParam, Class<T> responseType) {
        HttpEntity<String> requestEntity = new HttpEntity<>(null, makeHeader());
        LoadBalancerClient loadBalancerClient = SpringContextHolder.getBean(LoadBalancerClient.class);
        ServiceInstance serviceInstance = loadBalancerClient.choose(serviceName);
        String url = String.format("http://%s:%s", serviceInstance.getHost(), serviceInstance.getPort()) + uri + mapToUrlParam(requestParam);
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate.exchange(url, HttpMethod.GET, requestEntity, responseType, new HashMap<>());
    }

    private static HttpHeaders makeHeader() {
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes != null) {
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            String accessToken = request.getHeader(HttpHeaderKey.ACCESS_TOKEN);
            if (accessToken != null && !accessToken.isEmpty()) {
                headers.add(HttpHeaderKey.ACCESS_TOKEN, accessToken);
            }
        }
        return headers;
    }

    private static String mapToUrlParam(Map<String, ?> requestParam) {
        if (requestParam == null) {
            return Symbol.EMPTY_STR;
        }
        StringBuilder builder = new StringBuilder();
        builder.append(Symbol.QUESTION_MARK_STR);
        Set<String> keys = requestParam.keySet();
        for (String key : keys) {
            builder.append(key);
            builder.append(Symbol.EQUAL_STR);
            Object v = requestParam.get(key);
            if (v != null) {
                builder.append(URLEncoder.encode(v.toString(), StandardCharsets.UTF_8));
            }
            builder.append(Symbol.AND_STR);
        }
        String urlParam = builder.toString();
        if (urlParam.endsWith(Symbol.AND_STR)) {
            return urlParam.substring(0, urlParam.length() - 1);
        }
        return builder.toString();
    }

}
